package b.gate.pcks.fix

import java.lang.reflect.{ParameterizedType, Type => JavaType}

import b.gate.pcks.{CC填充, E填充方式, SerializerUtils, T报文适配器}

import scala.collection.mutable.ListBuffer
import scala.reflect.Manifest
import b.gate.utils._

/**
  * 定长报文格式适配。
  *
  * 贲国称 于 16/9/8 创建。
  */
object O定长报文适配器 extends T报文适配器 {
  def f拆报文成对象[A](v报文: Array[Byte], v报文定义: CC定长报文)(implicit mf: Manifest[A]): A = {
    val v域值s = f拆报文(v报文, v报文定义)
    f构建对象[A](v域值s, v报文定义)(mf)
  }
  def f拆报文(v报文: Array[Byte], v报文定义: CC定长报文): List[Array[Byte]] = {
    val v域长度s = v报文定义.v报文域s.map(_.v域长度)
    if (v报文.length < v域长度s.sum)
      throw CC系统内部错(s"报文长度[${v报文.length}]不足[${v域长度s.sum}]")
    val v剪裁s = List[Int](0) ++ (1 to v域长度s.length).toList.map(i => v域长度s.take(i).sum)
    v剪裁s.sliding(2).map { v剪裁 => v报文.slice(v剪裁.head, v剪裁.last) }.toList
  }
  def f构建对象[A](v域值s: List[Array[Byte]], v报文定义: CC定长报文)(implicit mf: Manifest[A]): A = {
    val v对象类型 = mf.runtimeClass
    val v成员s = v对象类型.getDeclaredFields
    val v成员变量名s = v成员s.map(_.getName).toList
    val v构建参数s = v对象类型.getDeclaredConstructors.head.getGenericParameterTypes
    // 对case class来说, 成员就是建构方法的构建参数
    def f查泛型类(v: String): Class[_] = {
      val v参数类型 = v构建参数s(v成员变量名s.indexOf(v))
      v参数类型.asInstanceOf[ParameterizedType].getActualTypeArguments.head.asInstanceOf[Class[_]]
    }
    val v成员变量值s = v成员s.map { v成员 =>
      val v成员序号 = v成员变量名s.indexOf(v成员.getName)
      v成员.getType match {
        case t: Class[_] if t == classOf[Option[_]] =>
          val v泛型类 = f查泛型类(v成员.getName)
          val x泛型类 = if (v泛型类 != classOf[java.lang.Object]) v泛型类 else
            SerializerUtils.findPrimitiveClass(v对象类型, v成员变量名s, v成员.getName)
          f提取变量值(x泛型类, v域值s(v成员序号), v报文定义.v报文域s(v成员序号))
        case t: Class[_] if f是元类型_?(t) =>
          f提取变量值(t, v域值s(v成员序号), v报文定义.v报文域s(v成员序号)).getOrElse(throw CC系统内部错(s"未找到[${v成员.getName}]的值"))
        case _ => throw new Error("不支持的类型")
      }
    }
    v对象类型.getConstructors.head.newInstance(v成员变量值s.map(_.asInstanceOf[AnyRef]).toArray: _*).asInstanceOf[A]
  }
  private def f提取变量值(v类型: Class[_], v域值: Array[Byte], v域: CC定长报文域): Option[Any] = {
    val x域值 = new String(v域值, "GBK")
    Option (
      if (v类型 == classOf[Int]) x域值.trim.toInt
      else if (v类型 == classOf[Long]) x域值.trim.toLong
      else if (v类型 == classOf[String]) {
        val z域值 = if (v域.v去空白) x域值.trim else x域值
        if (v域.v去空白 && z域值.isEmpty) null else z域值
      }
      else if (v类型 == classOf[BigDecimal]) BigDecimal(x域值.trim)
      else { throw CC系统内部错(s"不支持的数据类型[${v类型.getName}") }
    )
  }
  def f组报文[A](v对象: A, v报文定义: CC定长报文): Array[Byte] = {
    val v成员s = v对象.getClass.getDeclaredFields
    if (v成员s.length < v报文定义.v报文域s.length)
      throw CC系统内部错(s"[${v对象.getClass}]对象的成员变量不足以匹配报文[${v报文定义.v报文Id}]")
    var buffer = ListBuffer[Byte]()
    for (i <- v报文定义.v报文域s.indices) {
      val v域 = v报文定义.v报文域s(i)
      val v成员 = v成员s(i)
      println(s"$i : $v成员 by $v域")
      v成员.setAccessible(true)
      val z域值 = Option(v成员.get(v对象)) match {
        case Some(v变量值) =>
          if (v成员.getType != classOf[Option[_]]) Some(v变量值) else v变量值.asInstanceOf[Option[_]]
        case None => None
      }
      val v域值 = z域值 match {
        case Some(v变量值) => v变量值.toString.getBytes("GBK")
        case None =>
          v域.v默认值 match {
            case Some(v默认值) => v默认值.toString.getBytes("GBK")
            case None => Array.empty[Byte]
          }
      }
      val x域值 = v域.v填充.v方式 match {
        case E填充方式.e等长 =>
          if (v域值.length != v域.v域长度)
            throw CC系统内部错(s"第[${i+1}]个域[${v域.v域Id}]值长度[${v域值.length}]不等长于[${v域.v域长度}]")
          v域值
        case E填充方式.e不填 =>
          if (v域值.length < v域.v域长度)
            throw CC系统内部错(s"第[${i+1}]个域[${v域.v域Id}]值长度[${v域值.length}]不足[${v域.v域长度}]")
          v域值.take(v域.v域长度)
        case E填充方式.e后填 =>
          v域值.padTo(v域.v域长度, v域.v填充.v字符)
        case E填充方式.e前填 =>
          v域值.reverse.padTo(v域.v域长度, v域.v填充.v字符).reverse
      }
      buffer ++= x域值
    }
    buffer.toArray
  }
}
